/*
============================================================================
 Name        : StreamBuffer.cpp
 Author      : 
 Version     :
 Copyright   : Your copyright notice
 Description : CStreamBuffer implementation
============================================================================
*/

#include "StreamBuffer.h"
#include "StreamReader.h"
#include "StreamWriter.h"

#include "PluginUtility.h"

#define DEFAULT_BUFFER_SIZE 1048576


EXPORT_C CStreamBuffer::CStreamBuffer()
:	iBufferPtr(NULL, 0, 0), iFinished(EFalse)
{
	//Default values for sizes and factor
	iBufferSize = DEFAULT_BUFFER_SIZE;
}

EXPORT_C CStreamBuffer::~CStreamBuffer()
{
	iBufferPtr.Set(NULL, 0, 0);
	delete iBuffer;
}

EXPORT_C void CStreamBuffer::ConstructL()
{
	//Allocate the main buffer
	iBuffer = new (ELeave) TUint8[iBufferSize];
	iBufferPtr.Set(iBuffer, 0, iBufferSize);
}

EXPORT_C void CStreamBuffer::Start()
{
	iPosWritten = 0;
	iPosRead = 0;
	iFinished = EFalse;
}

TBool CStreamBuffer::IsReadyToWrite(TInt aLength)
{
	TInt diff = CalculateDifference(iPosWritten, iPosRead);
	return (diff + aLength < iBufferSize);
}

EXPORT_C void CStreamBuffer::Write(TDesC8& aChunk)
{
	//Length of data chunk
	TInt lengthWritten = aChunk.Length();

	//Offset will be > 0 if buffer is complete and we have to write data at the beginning again
	TInt offset = 0;
	if (iPosWritten + lengthWritten > iBufferSize)
	{
		//Calculate offset
		offset = iBufferSize - iPosWritten;
		
		//Copy data
		TPtr8 ptr(iBuffer + iPosWritten, offset, offset);
		ptr.Copy(aChunk.Left(offset));
		
		//Recalculate positions
		lengthWritten -= offset;
		iPosWritten = 0;
	}

	//Copy data
	TPtr8 ptr(iBuffer + iPosWritten, lengthWritten, lengthWritten);
	ptr.Copy(aChunk.Mid(offset, lengthWritten));

	//Advance written position
	iPosWritten += lengthWritten;
}

TInt CStreamBuffer::GetBytesReadyToRead()
{
	return CalculateDifference(iPosWritten, iPosRead);
}

void CStreamBuffer::Read(TDes8* aBuffer, TInt aLength)
{
	TInt offset = 0;
	if (iPosRead + aLength > iBufferSize)
	{
		//Calculate offset
		offset = iBufferSize - iPosRead;
		
		//Copy data
		aBuffer->Copy(iBuffer + iPosRead, offset);
		
		//Recalculate positions
		aLength -= offset;
		iPosRead = 0;
	}

	//Copy data
	aBuffer->Append(iBuffer + iPosRead, aLength);

	//Advance read position
	iPosRead += aLength;

	//Check if reader can write
	iReader->WriteToBuffer();
}

TInt CStreamBuffer::CalculateDifference(TInt aPos1, TInt aPos2)
{
	return ((aPos1 >= aPos2) ? aPos1 - aPos2 : aPos1 - aPos2 + iBufferSize);
}
